package com.hope;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Reflection01 {
    public static void main(String[] args) throws Exception {
        //根据配置文件 re.properties 指定信息，创建Cat对象并调用方法hi

//        传统的方法 new 对象 --> 调用方法
//        Cat cat=new Cat();
//        cat.hi();---> cat.cry(); 传统方法要修改源码


        //1. 使用 Properties类，可以读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("reflection/src/main/resources/re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String methodName = properties.get("method").toString();

        System.out.println("classfullpath=" + classfullpath);
        System.out.println("methodName=" + methodName);
        System.out.println("======================");
        //2. 创建对象 ，传统方法行不通，=》 反射机制
        //new classfullpath 因为通过Properties类读取配置文件 得到的classfullpath 是String

        //3. 使用反射机制解决
        //（1）加载类 返回Class类型的对象
        Class cls = Class.forName(classfullpath);
        //（2）通过 cls 得到你加载的类的 com.hope.cat 对象的实例
        Object o = cls.getDeclaredConstructor().newInstance();
        Object o1 = cls.getDeclaredConstructor().newInstance();
//        getClass(）返回Class类型的对象
        System.out.println("o的运行类型=" + o.getClass());//打印运行类型
        // (3) 通过class得到你加载的类 com.hope.Cat的methodName"hi"的方法对象
        // 即：在反射中，可以把方法视为 对象 （万物皆对象）
        Method method1 = cls.getMethod(methodName);
        //（4）传统方法 对象.方法() 反射：方法对象.invoke(类对象实例)
        method1.invoke(o);


//       3. java.lang.reflect.Field:  代表类的成员变量，Field对象表示某个类的成员变量
//        得到name字段
//        getField不能得到私有的属性
        Field nameField = cls.getField("age");
        System.out.println(nameField.get(o1));
        //反射：成员变量对象.get(对象) nameField.get(o)


        //传统写法，对象.成员变量
//      Cat.java 通过 javac 编译 生成 ->Cat.class字节码文件  通过类加载器ClassLoader 加载类，
//      加载完类后此时将已经编译后的 class字节码文件中的 成员变量，方法，构造器等等加载到java虚拟机堆中，并把他们变成数据结构
//      并返回Class类型到对象Class cls
//      通过对象 cls.getDeclaredConstructor().newInstance()方法创建cls对象实例


        //4.java.lang.reflect.Constructtor: 代表类的构造方法,Constructor对象表示构造器
        Constructor constructor = cls.getConstructor();//()中可以指定构造器参数，这里为空就是无参构造器
        System.out.println("这里打印到是无参构造器: " + constructor);

        //这里传入的String.class就是String类的Class对象
        Constructor constructor2 = cls.getConstructor(String.class);
        System.out.println(constructor2);



    }


}
